//
//  EzHlsMemoryLive.cpp
//  FFTEST_HLS
//
//  Created by 刘跃龙 on 9/30/18.
//  Copyright © 2018 absolutemobile. All rights reserved.
//

#include "EzHlsMemoryLive.hpp"

#include <string>
#include "ABMUtils.h"
#include "EzText.h"
#include "cocos2d.h"

#include "AccountData.h"

#ifdef __cplusplus
extern "C"
{
#endif
#include "ez_crc32.h"
#ifdef __cplusplus
};
#endif

EZ_BEGIN

EzHlsMemoryLive::EzHlsMemoryLive()
:m_fileNumber(-1)
,m_maxDuration(EZ_HLS_LIVE_MAX_DURATION)
,m_provider_name("Ezhomelabs")
,m_service_name("Service")
,m_pmt_pid(0x1000)
,m_program_number(0x0001)
,m_h264_pid(0x100)
,m_acc_pid(0x101)
,m_videoFrequency(1000)
,m_audioFrequency(1000)
,m_systemClockFrequency(27000000)
,m_startTime(0xFFFFFFFF)
,m_lastTimesmtmap(0xFFFFFFFFFFFFFFFF)
,m_offsetTime(0)
{
    m_itemList.clear();
    createNewTs();
//    testList.clear();
//    testList.append("#EXTM3U\n");
//    testList.append("#EXT-X-VERSION:3\n");
//    testList.append("#EXT-X-TARGETDURATION:"+ABMUtils::itoa(m_maxDuration)+"\n");
//    testList.append(std::string("#EXT-X-MEDIA-SEQUENCE:") + ABMUtils::itoa(m_fileNumber) + "\n");
}

EzHlsMemoryLive::~EzHlsMemoryLive()
{}

#include <map>
int EzHlsMemoryLive::getCountinuityCounter(int pid){
    static std::map<int,int> cclist;
    if(cclist[pid]<0x00||cclist[pid]>0xf) cclist[pid] = 0x00;
    int ret = cclist[pid];
    cclist[pid] = cclist[pid] + 1;
    return ret;
}

std::string EzHlsMemoryLive::getTsHeader(uint8_t payload_unit_start_indicator,uint16_t pid,uint8_t adaptation_field_control)
{
    std::string header = "";
    uint8_t sync_byte = 0x47;//起始位
    header.append(1,sync_byte);
    uint16_t temp_uint16 = 0;
    uint16_t tei = 0;//Transport Error Indicator (TEI) 通常是 0
    temp_uint16 += (tei & 0x01) << 15;
    //payload_unit_start_indicator 负载单元起始标示符，一个完整的数据包开始时标记为1
    temp_uint16 += (payload_unit_start_indicator & 0x01) << 14;
    uint16_t transport_priority = 0;//传输优先级，0为低优先级，1为高优先级，通常取0
    temp_uint16 += (transport_priority & 0x01) << 13;
    temp_uint16 += (pid & 0x1fff);
    header.append(EzText::uint16ToNetworkString(temp_uint16));
    uint8_t temp_uint8 = 0;
    uint8_t tsc = 0;//传输加扰控制，00表示未加密
    temp_uint8 += (tsc & 0x03) << 6;
    //adaptation_field_control 是否包含自适应区，‘00’保留；‘01’为无自适应域，仅含有效负载；‘10’为仅含自适应域，无有效负载；‘11’为同时带有自适应域和有效负载。
    temp_uint8 += (adaptation_field_control & 0x03) << 4;
    temp_uint8 += (getCountinuityCounter(pid) & 0x0f);//递增计数器，从0-f，起始值不一定取0，但必须是连续的
    header.append(1,temp_uint8);
    return header;
}

void EzHlsMemoryLive::cleanData(){
    m_fileNumber = -1;
    m_maxDuration = EZ_HLS_LIVE_MAX_DURATION;
    m_provider_name = "Ezhomelabs";
    m_service_name = "Service";
    m_pmt_pid = 0x1000;
    m_program_number = 0x0001;
    m_h264_pid = 0x100;
    m_acc_pid = 0x101;
    m_videoFrequency = 1000;
    m_audioFrequency = 1000;
    m_systemClockFrequency = 27000000;
    m_startTime = 0xFFFFFFFF;
    m_lastTimesmtmap = 0xFFFFFFFFFFFFFFFF;
    m_offsetTime = 0;
    m_item_mtx.Lock();
    for (std::list<EzHlsMemoryLive::HLSItem*>::iterator iter = m_itemList.begin(); iter != m_itemList.end(); iter++) {
        free((*iter)->pData);
        delete (*iter);
    }
    m_itemList.clear();
    m_item_mtx.UnLock();
    createNewTs();
}

void EzHlsMemoryLive::createNewTs()
{
    m_fileNumber++;
    m_Cache_mtx.Lock();
    m_tsCache.clear();
    m_Cache_mtx.UnLock();
    writePacket(getTsPacket_SDT());
    writePacket(getTsPacket_PAT());
    writePacket(getTsPacket_PMT());
    return;
}

void EzHlsMemoryLive::writePacket(std::string packet)
{
    m_Cache_mtx.Lock();
    m_tsCache.append(packet);
    m_Cache_mtx.UnLock();
}

void EzHlsMemoryLive::getTsH264PesPacket(uint32_t timestmap,std::string &data)
{
    //    log("HLS:VIDEO :%s\n",ABMUtils::aToHexString(data.substr(0,5)).c_str());
    
    std::string pes = "";
    pes.append(2,0x00);//start_code
    pes.append(1,0x01);//start_code
    uint8_t streamId = 0xe0;//H264 视频取值（0xe0-0xef），通常为0xe0
    pes.append(1,streamId);
    std::string pts = getPTS(timestmap, m_videoFrequency);
    size_t size = 0;
    size = 3 + 6 + pts.size() + data.size();
    
    //    if(size > 0xffff){
    pes.append(2,0);//0x0000表示不限定长度(帧16字节可以表示时，是否可用0x0000)
    //    }else{
    //        pes.append(1,((size >> 8) & 0xff));
    //        pes.append(1,(size & 0xff));
    //    }
    pes.append(1,0x80);//通常取值0x80，表示数据不加密、无优先级、备份的数据
    pes.append(1,0x80);//取值0x80表示只含有pts，取值0xc0表示含有pts和dts
    pes.append(1,0x05);// 05 后面数据的长度，取值5或10，如果是10，后面还有dts
    pes.append(pts);
    
    //    H.264 video access units must use Access Unit Delimiter NALs, and must be in unique PES packets.
    pes.append(3,0x00);//start_code
    pes.append(1,0x01);//start_code
    pes.append(1,0x09);//Access Unit Delimiter NALs
    pes.append(1,0xf0);//unknow
    
    data.insert(0, pes);
    //    log("HLS:VIDEO PES:%s\n",ABMUtils::aToHexString(pes.substr(0,100)).c_str());
}

void EzHlsMemoryLive::getTsAACPesPacket(uint32_t timestmap,std::string &data)
{
    //000001 c0 0b04 80 80 05 210007d861
    std::string pes = "";
    pes.append(2,0x00);//start_code
    pes.append(1,0x01);//start_code
    uint8_t streamId = 0xc0;//AAC 音频取值（0xc0-0xdf），通常为0xc0
    pes.append(1,streamId);
    std::string pts = getPTS(timestmap, m_audioFrequency);
    size_t size = 3 + pts.size() + data.size();
    if(size > 0xffff){
        pes.append(2,0);//0x0000表示不限定长度(帧16字节可以表示时，是否可用0x0000)
    }else{
        pes.append(1,((size >> 8) & 0xff));
        pes.append(1,(size & 0xff));
    }
    pes.append(1,0x80);//通常取值0x80，表示数据不加密、无优先级、备份的数据
    pes.append(1,0x80);//取值0x80表示只含有pts，取值0xc0表示含有pts和dts
    pes.append(1,0x05);// 05 后面数据的长度，取值5或10，如果是10，后面还有dts
    pes.append(pts);
    //    pes.append(adts);
    data.insert(0, pes);
    //log("HLS:AUDIO PES:%s\n",ABMUtils::aToHexString(pes.substr(0,100)).c_str());
}

void EzHlsMemoryLive::updateItem(float duration)
{
//    int currentDuration = ((int)duration+1);
//    m_maxDuration = m_maxDuration>currentDuration?m_maxDuration:currentDuration;
    if(duration>m_maxDuration) duration = m_maxDuration;
    char temp[32];
    memset(temp, 0, 32);
    sprintf(temp,"%f",duration);
    EzHlsMemoryLive::HLSItem* item = new HLSItem();
    item->index = m_fileNumber;
    item->duration = std::string(temp);
    item->fileName = ABMUtils::itoa(m_fileNumber) + ".ts";
    
    item->pData = (char*)malloc(m_tsCache.size());
    item->uDataSize = m_tsCache.size();
    memcpy(item->pData, m_tsCache.data(), m_tsCache.size());
    createNewTs();
    
//    std::string newFileName = "/mnt/mmc/test/"+item.fileName;
//    FILE* fp = fopen(newFileName.c_str(), "wb");
//    if (fp) {
//        fwrite(item.data.data(), item.data.size(), 1, fp);
//        fclose(fp);
//        fp = NULL;
//    }
//    testList.append(std::string("#EXTINF:") + item.duration + "\n");
//    testList.append(item.fileName+"\n");
//    if(m_fileNumber == 100){
//        std::string newFileName1 = "/mnt/mmc/test/index.m3u8";
//        FILE* fp1 = fopen(newFileName1.c_str(), "wb");
//        if (fp1) {
//            fwrite(testList.data(),testList.size(), 1, fp1);
//            fclose(fp1);
//            fp1 = NULL;
//        }
//    }
    m_item_mtx.Lock();
    m_itemList.push_back(item);
    if (m_itemList.size() > EZ_HLS_LIVE_FILE_COUNT) {
        free(m_itemList.front()->pData);
        delete m_itemList.front();
        m_itemList.pop_front();
    }
    m_item_mtx.UnLock();
}

uint32_t EzHlsMemoryLive::timestmapCorrecting(uint32_t timestmap)
{
//    printf("HLS:%d\n",timestamp);
//    if(m_lastTimesmtmap == 0xFFFFFFFFFFFFFFFF){
//        m_lastTimesmtmap = timestmap;
//        return timestmap;
//    }else{
//        int64_t diff = (int64_t)timestmap - m_lastTimesmtmap;
//        m_lastTimesmtmap = timestmap;
//        if(diff < -3000 || diff > 3000){//timebase = 1000 小于负3秒或者大于正3秒认为时间存在问题
//            printf("HLS:####################################################\n");
//            printf("HLS:ERROR TIMESTMAP %lld \n",diff);
//            printf("HLS:####################################################\n");
//            m_offsetTime += diff;
//        }
//        timestmap = (int64_t)timestmap - m_offsetTime;
//    }
    return timestmap;
}

void EzHlsMemoryLive::videoData(uint32_t timestmap,std::string &data)
{
//    timestmap = timestmapCorrecting(timestmap);
    
    uint8_t nal_unit_type = ((uint8)(data.at(4))) & 0x1f;
    if(nal_unit_type == 7){//key:sps+pps+I
        if(m_startTime == 0xFFFFFFFF){
            m_startTime = timestmap;//m_startTime初始化
        }
        float duration  = (timestmap - m_startTime)*1.0f/m_videoFrequency;
        if(duration >= EZ_HLS_LIVE_MIN_DURATION){
//            printf("HLS:duration ==> %u-%u=%f\n",timestmap,m_startTime,duration);
            updateItem(duration);
            m_startTime = timestmap;
        }else{
            writePacket(getTsPacket_PAT());
            writePacket(getTsPacket_PMT());
        }
    }else if(nal_unit_type == 1){//
        if(m_fileNumber<0) return;
    }else{
        return;
    }
    
//    printf("HLS:VIDEO<%f>[%lu]:%s\n",timestmap*1.0f/m_videoFrequency,data.size(),ABMUtils::aToHexString(data.substr(0,100)).c_str());
    getTsH264PesPacket(timestmap,data);//data->pes
    bool start = true;
    size_t handlePos = 0;
    size_t pesSize = data.size();
    while(true){
        std::string packet;
        if(start){
            packet.append(getTsHeader(Ez_HLS_UNIT_START, m_h264_pid, Ez_HLS_ADAPTATION_PAYLOAD)); // 4 Byte
            if((pesSize-handlePos) < TS_PACKET_SIZE - 12){
                std::string adaptationField = getTsAdaptationField_start_PCR(timestmap,m_videoFrequency,TS_PACKET_SIZE - (pesSize-handlePos) - 12);
                packet.append(adaptationField);
                packet.append(data.substr(handlePos));
                //log("HLS:video PES:%s\n",ABMUtils::aToHexString(packet).c_str());
                //                if(packet.size() != TS_PACKET_SIZE){
                //                    log("HLS:error PES:%s\n",ABMUtils::aToHexString(packet).c_str());
                //                    log("HLS:error\n");
                //                }
                writePacket(packet);
                break;
            }else{
                std::string adaptationField = getTsAdaptationField_start_PCR(timestmap,m_videoFrequency); // 8 Byte
                packet.append(adaptationField);
                size_t len = TS_PACKET_SIZE - packet.size();
                packet.append(data.substr(handlePos,len));
                //log("HLS:video PES:%s\n",ABMUtils::aToHexString(packet).c_str());
                //                if(packet.size() != TS_PACKET_SIZE){
                //                    log("HLS:error PES:%s\n",ABMUtils::aToHexString(packet).c_str());
                //                    log("HLS:error\n");
                //                }
                writePacket(packet);
                start = false;
                handlePos += len;
                if(handlePos==pesSize) break;
            }
        }else{
            if((pesSize-handlePos) < TS_PACKET_SIZE - 4){
                packet.append(getTsHeader(Ez_HLS_NOT_UNIT_START, m_h264_pid, Ez_HLS_ADAPTATION_PAYLOAD));
                std::string adaptationField = getTsAdaptationField_stuffing(TS_PACKET_SIZE - (pesSize-handlePos) - 4);
                packet.append(adaptationField);
                packet.append(data.substr(handlePos));
                //log("HLS:video PES:%s\n",ABMUtils::aToHexString(packet).c_str());
                //                if(packet.size() != TS_PACKET_SIZE){
                //                    log("HLS:error PES:%s\n",ABMUtils::aToHexString(packet).c_str());
                //                    log("HLS:error\n");
                //                }
                writePacket(packet);
                break;
            }else{
                packet.append(getTsHeader(Ez_HLS_NOT_UNIT_START, m_h264_pid, Ez_HLS_ONLY_PAYLOAD));
                size_t len = TS_PACKET_SIZE -  packet.size();
                packet.append(data.substr(handlePos,len));
                //log("HLS:video PES:%s\n",ABMUtils::aToHexString(packet).c_str());
                //                if(packet.size() != TS_PACKET_SIZE){
                //                    log("HLS:error PES:%s\n",ABMUtils::aToHexString(packet).c_str());
                //                    log("HLS:error\n");
                //                }
                writePacket(packet);
                handlePos += len;
                if(handlePos==pesSize) break;
            }
        }
    }
}

void EzHlsMemoryLive::audioData(uint32_t timestmap,std::string &data)
{
//    timestmap = timestmapCorrecting(timestmap);
    
    if(m_fileNumber<0) return;
    
//    printf("HLS:AUDIO<%f>[%lu]:%s\n",timestmap*1.0f/m_audioFrequency,data.size(),ABMUtils::aToHexString(data.substr(0,100)).c_str());
    getTsAACPesPacket(timestmap,data);//data->pes
    bool start = true;
    size_t handlePos = 0;
    size_t pesSize = data.size();
    while(true){
        std::string packet;
        if(start){
            packet.append(getTsHeader(Ez_HLS_UNIT_START,m_acc_pid, Ez_HLS_ADAPTATION_PAYLOAD)); // 4 Byte
            if((pesSize-handlePos) < TS_PACKET_SIZE - 6){
                std::string adaptationField = getTsAdaptationField_start(TS_PACKET_SIZE - (pesSize-handlePos) - 6);
                packet.append(adaptationField);
                packet.append(data.substr(handlePos));
                //log("HLS:audio PES:%s\n",ABMUtils::aToHexString(packet).c_str());
                //                if(packet.size() != TS_PACKET_SIZE){
                //                    log("HLS:error PES:%s\n",ABMUtils::aToHexString(packet).c_str());
                //                    log("HLS:error\n");
                //                }
                writePacket(packet);
                break;
            }else{
                std::string adaptationField = getTsAdaptationField_start(); // 8 Byte
                packet.append(adaptationField);
                size_t len = TS_PACKET_SIZE - packet.size();
                packet.append(data.substr(handlePos,len));
                //log("HLS:audio PES:%s\n",ABMUtils::aToHexString(packet).c_str());
                //                if(packet.size() != TS_PACKET_SIZE){
                //                    log("HLS:error PES:%s\n",ABMUtils::aToHexString(packet).c_str());
                //                    log("HLS:error\n");
                //                }
                writePacket(packet);
                start = false;
                handlePos += len;
                if(handlePos==pesSize) break;
            }
        }else{
            if((pesSize-handlePos) < TS_PACKET_SIZE - 4){
                packet.append(getTsHeader(Ez_HLS_NOT_UNIT_START, m_acc_pid, Ez_HLS_ADAPTATION_PAYLOAD));
                std::string adaptationField = getTsAdaptationField_stuffing(TS_PACKET_SIZE - (pesSize-handlePos) - 4);
                packet.append(adaptationField);
                packet.append(data.substr(handlePos));
                //log("HLS:audio PES:%s\n",ABMUtils::aToHexString(packet).c_str());
                //                if(packet.size() != TS_PACKET_SIZE){
                //                    log("HLS:error PES:%s\n",ABMUtils::aToHexString(packet).c_str());
                //                    log("HLS:error\n");
                //                }
                writePacket(packet);
                break;
            }else{
                packet.append(getTsHeader(Ez_HLS_NOT_UNIT_START, m_acc_pid, Ez_HLS_ONLY_PAYLOAD));
                size_t len = TS_PACKET_SIZE -  packet.size();
                packet.append(data.substr(handlePos,len));
                //log("HLS:audio PES:%s\n",ABMUtils::aToHexString(packet).c_str());
                //                if(packet.size() != TS_PACKET_SIZE){
                //                    log("HLS:error PES:%s\n",ABMUtils::aToHexString(packet).c_str());
                //                    log("HLS:error\n");
                //                }
                writePacket(packet);
                handlePos += len;
                if(handlePos==pesSize) break;
            }
        }
    }
}

uint8_t EzHlsMemoryLive::getAdaptationFieldFlag(uint8_t discontinuity_indicator//非连续提示符:值为1时说明基准时间戳发生变化，PCR值重置
                                               ,uint8_t random_access_indicator//随机访问提示符:值为1表示该PES包是一帧视频或者音频的起始包
                                               ,uint8_t elementary_stream_priority_indicator//元组流优先提示符:值为1表示ES包数据优先于其他包的数据
                                               ,uint8_t PCR_flag//PCR标志:值为1表示自适区存在PCR值(+ 6 Byte)
                                               ,uint8_t OPCR_flag//OPCR标志:值为1表示自适区存在OPCR值(+ 6 Byte)
                                               ,uint8_t splicing_point_flag//分割点标志:值为1表示存在splice_countdown字段(+ 1 Byte)
                                               ,uint8_t transport_private_data_flag//传输私有数据标志:值为1表示自适区内包含一段或多段私有数据(+ 1 Byte + n Byte)
                                               ,uint8_t adaptation_field_extension_flag//自适应区扩展标志:值为1 时表示自适区内存在扩展数据(+ n Byte)
)
{
    return ((discontinuity_indicator & 0x01)<<7) +
    ((random_access_indicator & 0x01)<<6) +
    ((elementary_stream_priority_indicator & 0x01)<<5) +
    ((PCR_flag & 0x01)<<4) +
    ((OPCR_flag & 0x01)<<3) +
    ((splicing_point_flag & 0x01)<<2) +
    ((transport_private_data_flag & 0x01)<<1) +
    ((adaptation_field_extension_flag & 0x01));
}

std::string EzHlsMemoryLive::getPCR(uint32_t timestmap,uint32_t frequency) //6 Byte
{
//    log("HLS:PCR:%f\n", 1.f * timestmap / frequency);
    std::string pcr = "";
    uint64_t pcr_base = ( ( m_systemClockFrequency * timestmap / frequency ) / 300) % 8589934592;//2^33;
    uint64_t pcr_ext   = ( ( m_systemClockFrequency * timestmap / frequency ) / 1 ) % 300;
    uint32_t temp_uint32 = ( pcr_base >> 1 ) & 0xFFFFFFFF ;
    pcr.append(EzText::uint32ToNetworkString(temp_uint32));
    uint32_t temp_uint16 = 0;
    temp_uint16 += ( pcr_base & 0x01 ) << 15;
    temp_uint16 += ( 0x3f & 0x3f ) << 9;
    temp_uint16 += ( pcr_ext & 0x1ff );
    pcr.append(EzText::uint16ToNetworkString(temp_uint16));
    //    log("HLS:[timestmap:%u,frequency:%u,pcr_base:%lu,pcr_ext:%lu]\n",timestmap,frequency,pcr_base,pcr_ext);
    //    log("HLS:PCR:%s\n",ABMUtils::aToHexString(pcr).c_str());
    return pcr;
}
std::string EzHlsMemoryLive::getPTS(uint32_t timestmap,uint32_t frequency){ // 5 Bytes
//    log("HLS:PTS:%f\n", 1.f * timestmap / frequency);
    std::string pts = "";
    uint64_t ptsValue = ((m_systemClockFrequency * timestmap / frequency) / 300) % 8589934592;//2^33;
    pts.append(1,0x20 | (((ptsValue >> 30) & 0x07) << 1) | 1);
    pts.append(1,((ptsValue >> 22) & 0xFF));
    pts.append(1,(((ptsValue >> 15) & 0x7F) << 1) | 1);
    pts.append(1,((ptsValue >> 7) & 0xFF));
    pts.append(1,((ptsValue & 0x7F) << 1) | 1);
    return pts;
}

std::string EzHlsMemoryLive::getDTS(uint32_t timestmap,uint32_t frequency)
{
    return getPTS(timestmap,frequency);
}

std::string EzHlsMemoryLive::getATDS(std::string dsi,size_t packetLen)
{
    packetLen +=7;
    uint8_t profile = (dsi.at(0) >> 3) & 0x03;//profile = object_type - 1
    uint8_t sampling_frequency_index = ((dsi.at(0) & 0x07) << 1) + ((dsi.at(1) >> 7) & 0x01);
    uint8_t channel_configuration = ((dsi.at(1) >> 3) & 0x07);
    std::string atds = "";
    atds.append(1,0xFF);
    atds.append(1,0xF1);//atds.append(1,0xF9);
    atds.append(1,((((profile-1) & 0x03) << 6) | ((sampling_frequency_index & 0x0F) << 2) | (channel_configuration>>2 & 0x01)));
    atds.append(1,(((channel_configuration & 0x03) << 6) | ((packetLen >> 11) & 0x03)));
    atds.append(1,((packetLen >> 3) & 0xFF));
    atds.append(1,((packetLen & 0x07) << 5) | 0x1f);
    atds.append(1,0xFC);
    return atds;
}

std::string EzHlsMemoryLive::getTsAdaptationField_stuffing(size_t size)
{
    std::string  adaptationFiled = "";
    if(size >= 2){
        adaptationFiled.append(1,((size-1) & 0xFF));
        adaptationFiled.append(1,getAdaptationFieldFlag(0,0,0,0,0,0,0,0));
        if(size - 2>0) adaptationFiled.append(size - 2,0xFF);
    }else if(size == 1){
        adaptationFiled.append(1,0x00);
    }
    return adaptationFiled;
}

std::string EzHlsMemoryLive::getTsAdaptationField_start_PCR(uint32 timestmap,uint32 frequency,size_t stuffingSize) // 8 Byte
{
    std::string pcr = getPCR(timestmap,frequency);
    std::string  adaptationFiled = "";
    adaptationFiled.append(1,pcr.size()+1+stuffingSize);
    adaptationFiled.append(1,getAdaptationFieldFlag(0,1,0,1,0,0,0,0));
    adaptationFiled.append(pcr);
    if(stuffingSize>0) adaptationFiled.append(stuffingSize,0xFF);
    return adaptationFiled;
}
std::string EzHlsMemoryLive::getTsAdaptationField_start(size_t stuffingSize) // 2 Byte
{
    std::string  adaptationFiled = "";
    adaptationFiled.append(1,1+stuffingSize);
    adaptationFiled.append(1,getAdaptationFieldFlag(0,1,0,0,0,0,0,0));
    if(stuffingSize>0) adaptationFiled.append(stuffingSize,0xFF);
    return adaptationFiled;
}

std::string EzHlsMemoryLive::getTsDescriptor_SDT()
{
    std::string descriptorContent = "";
    uint8_t service_type = 0x01;//(数字电视业务)
    std::string service_provider_name = m_provider_name;
    uint8_t service_provider_name_length = service_provider_name.size();
    descriptorContent.append(1,service_type);
    descriptorContent.append(1,service_provider_name_length);
    descriptorContent.append(service_provider_name);
    std::string service_name = m_service_name;
    uint8_t service_name_length = service_name.size();
    descriptorContent.append(1,service_name_length);
    descriptorContent.append(service_name);
    std::string descriptor = "";
    uint8_t descriptor_tag = 0x48;//??
    descriptor.append(1,descriptor_tag);
    uint8_t descriptor_length = descriptorContent.size();
    descriptor.append(1,descriptor_length);
    descriptor.append(descriptorContent);
    return descriptor;
}

std::string EzHlsMemoryLive::getSection_SDT()
{
    std::string section = "";
    uint16_t transport_stream_id = 0x0001;//当前描述的流ID
    section.append(EzText::uint16ToNetworkString(transport_stream_id));
    uint8_t temp_uint8 = 0;
    uint8_t reserved = 0x03;// 11
    temp_uint8 += (reserved & 0x03) << 6;
    uint8_t version_number = 0x00;
    temp_uint8 += (version_number & 0x1f) << 1;
    uint8_t current_next_indicator = 1;//当前未来标志,一般是''0'',表示当前马上使用.
    temp_uint8 += (current_next_indicator & 0x01);
    section.append(1,temp_uint8);
    uint8_t section_number = 0x00;
    section.append(1,section_number);
    uint8_t last_section_number = 0x00;
    section.append(1,last_section_number);
    uint16_t original_nerwork_id = 0xff01;
    section.append(EzText::uint16ToNetworkString(original_nerwork_id));
    uint8_t reserved_future_use1 = 0xff;
    section.append(1,reserved_future_use1);
    uint16_t service_id = 0x0001;
    section.append(EzText::uint16ToNetworkString(service_id));
    temp_uint8 = 0;
    uint8_t reserved_future_use2 = 0x3f;
    temp_uint8 += (reserved_future_use2 & 0x3f) << 2;
    uint8_t EIT_schedule_flag = 0;
    temp_uint8 += (EIT_schedule_flag & 0x01) << 1;
    uint8_t EIT_present_following_flag = 0;
    temp_uint8 += (EIT_present_following_flag & 0x01);
    section.append(1,temp_uint8);
    uint16_t temp_uint16 = 0;
    uint16_t running_status = 4;//运行中
    temp_uint16 +=(running_status & 0x07)<< 13;
    uint16_t freed_CA_mode = 0;
    temp_uint16 +=(freed_CA_mode & 0x01)<< 12;
    std::string descriptor = getTsDescriptor_SDT();
    uint16_t descriptors_loop_length = descriptor.size();
    temp_uint16 +=(descriptors_loop_length & 0x0fff);
    section.append(EzText::uint16ToNetworkString(temp_uint16));
    section.append(descriptor);
    return section;
}

std::string EzHlsMemoryLive::getTsPacket_SDT()
{
    std::string packet = "";
    packet.append(getTsHeader(Ez_HLS_UNIT_START,SDT_PID,Ez_HLS_ONLY_PAYLOAD));
    packet.append(1,0x00);//unknown 可能是 Adaptation Field Length 即使没有也保留一个长度
    uint8_t table_id = SDT_TID;//表示描述的是当前流的信息
    packet.append(1,table_id);
    uint16_t temp_uint16 = 0;
    uint16_t section_syntax_indicator = 1;//段语法标志,应该是 1
    temp_uint16 += (section_syntax_indicator & 0x01) << 15;
    uint16_t reserved_future_used = 0x03;//保留未来使用
    temp_uint16 += (reserved_future_used & 0x03) << 13;
    uint16_t reserved = 1;
    temp_uint16 += (reserved & 0x01) << 12;
    std::string section = getSection_SDT();
    uint16_t section_length = section.size() + 4;//crc32 4byte
    temp_uint16 += (section_length & 0x0fff);
    packet.append(EzText::uint16ToNetworkString(temp_uint16));
    packet.append(section);
    uint32_t crc32 = ez_crc32_mpeg2((void*)(packet.data()+5),(unsigned int)packet.size()-5);
    packet.append(EzText::uint32ToNetworkString(crc32));
    uint8_t fillChar = 0xff;
    packet.append(TS_PACKET_SIZE-packet.size(),fillChar);
    return packet;
}

std::string EzHlsMemoryLive::getSection_PAT()
{
    std::string section = "";
    uint16_t transport_stream_id = 0x0001;//当前描述的流ID
    section.append(EzText::uint16ToNetworkString(transport_stream_id));
    uint8_t temp_uint8 = 0;
    uint8_t reserved1 = 0x03;// 0b11
    temp_uint8 += (reserved1 & 0x03) << 6;
    uint8_t version_number = 0x00;
    temp_uint8 += (version_number & 0x1f) << 1;
    uint8_t current_next_indicator = 1;//当前未来标志,一般是''0'',表示当前马上使用.
    temp_uint8 += (current_next_indicator & 0x01);
    section.append(1,temp_uint8);
    uint8_t section_number = 0x00;
    section.append(1,section_number);
    uint8_t last_section_number = 0x00;
    section.append(1,last_section_number);
    uint16_t program_number = m_program_number;
    section.append(EzText::uint16ToNetworkString(program_number));
    uint16_t temp_uint16 = 0;
    uint16_t reserved2 = 0x07;// 0b111
    temp_uint16 +=(reserved2 & 0x07)<< 13;
    uint16_t pid = m_pmt_pid;
    temp_uint16 +=(pid & 0x1fff);
    section.append(EzText::uint16ToNetworkString(temp_uint16));
    return section;
}

std::string EzHlsMemoryLive::getTsPacket_PAT()
{
    std::string packet = "";
    packet.append(getTsHeader(Ez_HLS_UNIT_START, PAT_PID, Ez_HLS_ONLY_PAYLOAD));
    packet.append(1,0x00);//unknown 可能是 Adaptation Field Length 即使没有也保留一个长度
    uint8_t table_id = PAT_TID;//表示描述的是当前流的信息
    packet.append(1,table_id);
    uint16_t temp_uint16 = 0;
    uint16_t section_syntax_indicator = 1;//段语法标志,应该是 1
    temp_uint16 += (section_syntax_indicator & 0x01) << 15;
    uint16_t zero = 0x00;//保留未来使用
    temp_uint16 += (zero & 0x01) << 14;
    uint16_t reserved = 0x03;
    temp_uint16 += (reserved & 0x03) << 12;
    std::string section = getSection_PAT();
    uint16_t section_length = section.size() + 4;//crc32 4byte
    temp_uint16 += (section_length & 0x0fff);
    packet.append(EzText::uint16ToNetworkString(temp_uint16));
    packet.append(section);
    uint32_t crc32 = ez_crc32_mpeg2((void*)(packet.data()+5),(unsigned int)packet.size()-5);
    packet.append(EzText::uint32ToNetworkString(crc32));
    uint8_t fillChar = 0xff;
    packet.append(TS_PACKET_SIZE-packet.size(),fillChar);
    return packet;
}

std::string EzHlsMemoryLive::getSection_PMT()
{
    std::string section = "";
    uint16_t program_number = m_program_number;//频道
    section.append(EzText::uint16ToNetworkString(program_number));
    uint8_t temp_uint8 = 0;
    uint8_t reserved1 = 0x03;// 0b11
    temp_uint8 += (reserved1 & 0x03) << 6;
    uint8_t version_number = 0x00;
    temp_uint8 += (version_number & 0x1f) << 1;
    uint8_t current_next_indicator = 1;//当前未来标志,一般是''0'',表示当前马上使用.
    temp_uint8 += (current_next_indicator & 0x01);
    section.append(1,temp_uint8);
    uint8_t section_number = 0x00;
    section.append(1,section_number);
    uint8_t last_section_number = 0x00;
    section.append(1,last_section_number);
    uint16_t temp_uint16 = 0;
    uint16_t reserved2 = 0x07;// 0b111
    temp_uint16 +=(reserved2 & 0x07)<< 13;
    uint16_t pcr_pid = m_h264_pid;
    temp_uint16 +=(pcr_pid & 0x1fff);
    section.append(EzText::uint16ToNetworkString(temp_uint16));
    temp_uint16 = 0;
    uint16_t reserved3 = 0x0f;// 0b1111
    temp_uint16 +=(reserved3 & 0x0f)<< 12;
    uint16_t program_info_length = 0;//节目描述信息，指定为0x000表示没有
    temp_uint16 +=(program_info_length & 0x0fff);
    section.append(EzText::uint16ToNetworkString(temp_uint16));
    // H264
    uint8_t h264_stream_type = STREAM_TYPE_VIDEO_H264;
    section.append(1,h264_stream_type);
    temp_uint16 = 0;
    uint16_t reserved4 = 0x07;// 0b111
    temp_uint16 +=(reserved4 & 0x07)<< 13;
    uint16_t h264_pid = m_h264_pid;
    temp_uint16 +=(h264_pid & 0x1fff);
    section.append(EzText::uint16ToNetworkString(temp_uint16));
    temp_uint16 = 0;
    uint16_t reserved5 = 0x0f;// 0b1111
    temp_uint16 +=(reserved5 & 0x0f)<< 12;
    uint16_t h264_es_info_length = 0;//节目描述信息，指定为0x000表示没有
    temp_uint16 +=(h264_es_info_length & 0x0fff);
    section.append(EzText::uint16ToNetworkString(temp_uint16));
    // ACC
    uint8_t acc_stream_type = STREAM_TYPE_AUDIO_AAC;
    section.append(1,acc_stream_type);
    temp_uint16 = 0;
    uint16_t reserved6 = 0x07;// 0b111
    temp_uint16 +=(reserved6 & 0x07)<< 13;
    uint16_t acc_pid = m_acc_pid;
    temp_uint16 +=(acc_pid & 0x1fff);
    section.append(EzText::uint16ToNetworkString(temp_uint16));
    temp_uint16 = 0;
    uint16_t reserved7 = 0x0f;// 0b1111
    temp_uint16 +=(reserved7 & 0x0f)<< 12;
    uint16_t acc_es_info_length = 0;//节目描述信息，指定为0x000表示没有
    temp_uint16 +=(acc_es_info_length & 0x0fff);
    section.append(EzText::uint16ToNetworkString(temp_uint16));
    return section;
}

std::string EzHlsMemoryLive::getTsPacket_PMT()
{
    std::string packet = "";
    packet.append(getTsHeader(Ez_HLS_UNIT_START, m_pmt_pid,Ez_HLS_ONLY_PAYLOAD));
    packet.append(1,0x00);//unknown 可能是 Adaptation Field Length 即使没有也保留一个长度
    uint8_t table_id = PMT_TID;//表示描述的是当前流的信息
    packet.append(1,table_id);
    uint16_t temp_uint16 = 0;
    uint16_t section_syntax_indicator = 1;//段语法标志,应该是 1
    temp_uint16 += (section_syntax_indicator & 0x01) << 15;
    uint16_t zero = 0x00;//保留未来使用
    temp_uint16 += (zero & 0x01) << 14;
    uint16_t reserved = 0x03;
    temp_uint16 += (reserved & 0x03) << 12;
    std::string section = getSection_PMT();
    uint16_t section_length = section.size() + 4;//crc32 4byte
    temp_uint16 += (section_length & 0x0fff);
    packet.append(EzText::uint16ToNetworkString(temp_uint16));
    packet.append(section);
    uint32_t crc32 = ez_crc32_mpeg2((void*)(packet.data()+5),(unsigned int)packet.size()-5);
    packet.append(EzText::uint32ToNetworkString(crc32));
    uint8_t fillChar = 0xff;
    packet.append(TS_PACKET_SIZE-packet.size(),fillChar);
    return packet;
}

void EzHlsMemoryLive::getChcheFile(int cameraId,std::string filename,std::string token,std::string &res)
{
    std::string ret = "";
    if(filename.empty()){
        printf("HLS:[%s](404)\n",filename.c_str());
        res = getHttpRes404();
        return;
    }
    if(filename=="index.m3u8"){
        m_item_mtx.Lock();
        if(m_itemList.size() > 0){
            ret.append("#EXTM3U\n");
            ret.append("#EXT-X-VERSION:3\n");
            ret.append("#EXT-X-TARGETDURATION:"+ABMUtils::itoa(m_maxDuration)+"\n");
            int index = 0;
            int begin = -1;
            std::string list = "";
            std::string listlog;
            for (std::list<EzHlsMemoryLive::HLSItem*>::iterator it = m_itemList.begin() ; it != m_itemList.end() ; it++) {
                if(index < EZ_HLS_LIVE_FILE_HIDE && index < ((int)m_itemList.size()) - EZ_HLS_LIVE_FILE_SHOW ){
                    // hide before delete
                    listlog.append("{"+(*it)->fileName+","+(*it)->duration+"}");
                }else{
                    if(begin==-1) begin = (*it)->index;
                    list.append(std::string("#EXTINF:") + (*it)->duration + "\n");
                    list.append((*it)->fileName+"?id="+ABMUtils::itoa(cameraId));
                    if(!token.empty()) list.append("&token="+token);
                    list.append("\n");
                    listlog.append("["+(*it)->fileName+","+(*it)->duration+"]");
                    
                }
                index++;
            }
            ret.append(std::string("#EXT-X-MEDIA-SEQUENCE:") + ABMUtils::itoa(begin) + "\n");
            ret.append(list);
            printf("HLS:%s\n",listlog.c_str());
        }
        m_item_mtx.UnLock();
        if(ret.empty()){
            printf("HLS:[%s](404)[%d-%d]\n",filename.c_str(),m_fileNumber-EZ_HLS_LIVE_FILE_SHOW > 0 ? m_fileNumber-EZ_HLS_LIVE_FILE_SHOW:0,m_fileNumber-1>0?m_fileNumber-1:0);
            res = getHttpRes404();
        }else{
            printf("HLS:[%s](200)[%d-%d]\n",filename.c_str(),m_fileNumber-EZ_HLS_LIVE_FILE_SHOW > 0 ? m_fileNumber-EZ_HLS_LIVE_FILE_SHOW:0,m_fileNumber-1>0?m_fileNumber-1:0);
            res = getHttpRes200(ret);
//            log("HLS:----------------------------\n");
//            log("HLS:%s",ret.c_str());
//            log("HLS:----------------------------\n");
        }
    }else if(filename.size() >= 3 && filename.substr(filename.size()-3) == ".ts"){
        m_item_mtx.Lock();
        for (std::list<EzHlsMemoryLive::HLSItem*>::iterator it = m_itemList.begin() ; it != m_itemList.end() ; it++) {
            if((*it)->fileName == filename){
                ret = std::string((*it)->pData,(*it)->uDataSize);
                break;
            }
        }
        m_item_mtx.UnLock();
        if(ret.empty()){
            printf("HLS:[%s](404)[%d-%d]\n",filename.c_str(),m_fileNumber-EZ_HLS_LIVE_FILE_COUNT > 0 ? m_fileNumber-EZ_HLS_LIVE_FILE_COUNT:0,m_fileNumber-1>0?m_fileNumber-1:0);
//            res = getHttpRes404();
            res = getHttpRes200(ret);
        }else{
            printf("HLS:[%s](200)[%d-%d]\n",filename.c_str(),m_fileNumber-EZ_HLS_LIVE_FILE_COUNT > 0 ? m_fileNumber-EZ_HLS_LIVE_FILE_COUNT:0,m_fileNumber-1>0?m_fileNumber-1:0);
            res = getHttpRes200(ret);
        }
    }else{
        printf("HLS:[%s](404)\n",filename.c_str());
        res = getHttpRes404();
    }
}

std::string EzHlsMemoryLive::getHttpRes404()
{
    std::string ret = "HTTP/1.1 404 Not Found\r\nAccess-Control-Allow-Origin: *\r\nServer: YouIpCams/v1.0.0\r\nContent-Type: text/html\r\nConnection: Close\r\n\r\n";
    printf("HLS:----------------------------\n");
    printf("HLS:%s\n",ret.c_str());
    printf("HLS:----------------------------\n");
    return ret;
}

std::string EzHlsMemoryLive::getHttpRes200(std::string data)
{
    std::string ret = "HTTP/1.1 200 OK\r\nServer: YouIPCams/v1.0.0\r\nAccess-Control-Allow-Origin: *\r\nContent-Type: application/vnd.apple.mpegurl\r\nContent-Length: ";
    ret.append(ABMUtils::itoa((int)data.size()));
    ret.append("\r\nConnection: Close\r\n\r\n");
    printf("HLS:----------------------------\n");
    printf("HLS:%s\n",ret.c_str());
    printf("HLS:----------------------------\n");
    ret.append(data);
    return ret;
}

EZ_END
